using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

namespace virtuaPol.Model
{
    public enum CPropertyValueTypes
    {
        Integer,
        LongInt,
        Double,
        Boolean,
        String
    }

    //[System.Xml.Serialization.XmlType("property")]
    public class CProperty : virtuaPol.Util.INamedObject
    {
        // Locker object for thread safety
        private object _locker = new object();

        private String name;
        [System.Xml.Serialization.XmlAttribute("name")]
        public String Name
        {
            get { lock (_locker) { return name; } }
            set { lock (_locker) { name = value; } }
        }

        private string description;
        [System.Xml.Serialization.XmlElement("description")]
        public string Description
        {
            get { lock (_locker) { return description; } }
            set { lock (_locker) { description = value; } }
        }

        private CPropertyValueTypes type;
        [System.Xml.Serialization.XmlAttribute("type")]
        public CPropertyValueTypes Type
        {
            get { lock (_locker) { return this.type; } }
            set { lock (_locker) { this.type = value; } }
        }

        private object value;
        [System.Xml.Serialization.XmlElement("value")]
        public object Value
        {
            get { lock (_locker) { return this.value; } }
            set { lock (_locker) { this.value = value; FixValueType(); } }
        }

        public CProperty()
        { }

        public CProperty(string name, CPropertyValueTypes type, object value)
        {
            Name = name;
            Type = type;
            Value = value;
        }
        
        public static CProperty newInt32Property(string name, int value)
        {
            return new CProperty(name, CPropertyValueTypes.Integer, value);
        }
        public static CProperty newInt64Property(string name, long value)
        {
            return new CProperty(name, CPropertyValueTypes.LongInt, value);
        }
        public static CProperty newDoubleProperty(string name, double value)
        {
            return new CProperty(name, CPropertyValueTypes.Double, value);
        }
        public static CProperty newBoolProperty(string name, bool value)
        {
            return new CProperty(name, CPropertyValueTypes.Boolean, value);
        }
        public static CProperty newStringProperty(string name, string value)
        {
            return new CProperty(name, CPropertyValueTypes.String, value);
        }

        public int getInt32() {
            try { return (int)Value; }
            catch (InvalidCastException ex) { virtuaPol.Util.CLogger.LogError(ex); throw ex; }
        }
        public long getInt64() {
            try { return (long)Value; }
            catch (InvalidCastException ex) { virtuaPol.Util.CLogger.LogError(ex); throw ex; }
        }
        public double getDouble() {
            try { return (double)Value; }
            catch (InvalidCastException ex) { virtuaPol.Util.CLogger.LogError(ex); throw ex; }
        }
        public bool getBool() {
            try { return (bool)Value; }
            catch (InvalidCastException ex) { virtuaPol.Util.CLogger.LogError(ex); throw ex; }
        }
        public string getString() {
            try { return (string)Value; }
            catch (InvalidCastException ex) { virtuaPol.Util.CLogger.LogError(ex); throw ex; }
        }

        public void FixValueType()
        {
            Type valType = Value.GetType();

            switch (Type)
            {
                case CPropertyValueTypes.Boolean:
                    if (valType == typeof(bool)) return;

                    if (valType == typeof(string))
                    {
                        bool b;
                        if (Boolean.TryParse((string)Value, out b))
                            Value = b;
                        else Value = false;
                    }
                    else if (valType == typeof(int))
                        Value = (int)Value != 0;
                    else if(valType == typeof(long))
                        Value = (long)Value != (long)0;
                    else if (valType == typeof(double))
                        Value = (double)Value != 0.0;
                    break;
                case CPropertyValueTypes.Double:
                    if (valType == typeof(double)) return;

                    if (valType == typeof(string))
                    {
                        double dbl;
                        if (Double.TryParse((string)Value, out dbl))
                            Value = dbl;
                        else Value = 0.0;
                    }
                    else if (valType == typeof(int)
                        || valType == typeof(long))
                        Value = (double)Value;
                    else if (valType == typeof(bool))
                        Value = ((bool)Value ? 1.0 : 0.0);
                    break;
                case CPropertyValueTypes.Integer:
                    if (valType == typeof(int)) return;

                    if (valType == typeof(string))
                    {
                        int i;
                        if (Int32.TryParse((string)Value, out i))
                            Value = i;
                        else Value = 0;
                    }
                    else if (valType == typeof(double))
                        Value = (int)Math.Floor((double)Value);
                    else if (valType == typeof(long))
                        throw new InvalidCastException("Long int can't be converted to int");
                    else if (valType == typeof(bool))
                        Value = ((bool)Value ? 1 : 0);
                    break;
                case CPropertyValueTypes.LongInt:
                    if (valType == typeof(long)) return;

                    if (valType == typeof(string))
                    {
                        long l;
                        if (Int64.TryParse((string)Value, out l))
                            Value = l;
                        else Value = (long)0;
                    }
                    else if (valType == typeof(int))
                        Value = (long)Value;
                    else if (valType == typeof(double))
                        Value = (long)Math.Floor((double)Value);
                    else if (valType == typeof(bool))
                        Value = ((bool)Value ? (long)1 : (long)0);
                    break;
                case CPropertyValueTypes.String:
                    if (valType == typeof(string)) return;

                    Value = Value.ToString();
                    break;
            }
        }
    }
}
